﻿using System;
using System.Collections.ObjectModel;
using System.IO;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using Miris.HumanMilkAnalyser.DataModel;
using Miris.HumanMilkAnalyser.Service;
using Miris.HumanMilkAnalyser.WPF.Model;
using Miris.HumanMilkAnalyser.WPF.Shared;

namespace Miris.HumanMilkAnalyser.WPF.ViewModel
{
    /// <summary>
    /// This class contains properties that a View can data bind to.
    /// <para>
    /// See http://www.galasoft.ch/mvvm
    /// </para>
    /// </summary>
    public class BasicConfigurationViewModel : MyViewModelBase
    {
        BasicConfigurationService _basicConfigurationService;

        /// <summary>
        /// Initializes a new instance of the BasicConfigurationViewModel class.
        /// </summary>
        public BasicConfigurationViewModel(IDataService dataService)
            : base(dataService)
        {
            _basicConfigurationService = ServiceFactory.CreateBasicConfigurationService();
        }

        public override void ResetProperties()
        {
            base.ResetProperties();

            GenerateSerialPortNameList();
            GeneratePatientNumberInitializedSequenceList();
            SetProperties(_basicConfigurationService.Load());
        }

        /// <summary>
        /// The <see cref="PatientNumberPrefix" /> property's name.
        /// </summary>
        public const string PatientNumberPrefixPropertyName = "PatientNumberPrefix";

        private string _patientNumberPrefix = string.Empty;

        /// <summary>
        /// Sets and gets the PatientNumberPrefix property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string PatientNumberPrefix
        {
            get
            {
                return _patientNumberPrefix;
            }

            set
            {
                if (_patientNumberPrefix == value)
                {
                    return;
                }

                RaisePropertyChanging(PatientNumberPrefixPropertyName);
                _patientNumberPrefix = value;
                RaisePropertyChanged(PatientNumberPrefixPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="PatientNumberContainsYear" /> property's name.
        /// </summary>
        public const string PatientNumberContainsYearPropertyName = "PatientNumberContainsYear";

        private bool _patientNumberContainsYear = true;

        /// <summary>
        /// Sets and gets the PatientNumberContainsYear property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public bool PatientNumberContainsYear
        {
            get
            {
                return _patientNumberContainsYear;
            }

            set
            {
                if (_patientNumberContainsYear == value)
                {
                    return;
                }

                RaisePropertyChanging(PatientNumberContainsYearPropertyName);
                _patientNumberContainsYear = value;
                RaisePropertyChanged(PatientNumberContainsYearPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="PatientNumberContainsMonth" /> property's name.
        /// </summary>
        public const string PatientNumberContainsMonthPropertyName = "PatientNumberContainsMonth";

        private bool _patientNumberContainsMonth = true;

        /// <summary>
        /// Sets and gets the PatientNumberContainsMonth property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public bool PatientNumberContainsMonth
        {
            get
            {
                return _patientNumberContainsMonth;
            }

            set
            {
                if (_patientNumberContainsMonth == value)
                {
                    return;
                }

                RaisePropertyChanging(PatientNumberContainsMonthPropertyName);
                _patientNumberContainsMonth = value;
                RaisePropertyChanged(PatientNumberContainsMonthPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="PatientNumberContainsDay" /> property's name.
        /// </summary>
        public const string PatientNumberContainsDayPropertyName = "PatientNumberContainsDay";

        private bool _patientNumberContainsDay = true;

        /// <summary>
        /// Sets and gets the PatientNumberContainsDay property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public bool PatientNumberContainsDay
        {
            get
            {
                return _patientNumberContainsDay;
            }

            set
            {
                if (_patientNumberContainsDay == value)
                {
                    return;
                }

                RaisePropertyChanging(PatientNumberContainsDayPropertyName);
                _patientNumberContainsDay = value;
                RaisePropertyChanged(PatientNumberContainsDayPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="PatientNumberInitializedSequence" /> property's name.
        /// </summary>
        public const string PatientNumberInitializedSequencePropertyName = "PatientNumberInitializedSequence";

        private string _patientNumberInitializedSequence = string.Empty;

        /// <summary>
        /// Sets and gets the PatientNumberInitializedSequence property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string PatientNumberInitializedSequence
        {
            get
            {
                return _patientNumberInitializedSequence;
            }

            set
            {
                if (_patientNumberInitializedSequence == value)
                {
                    return;
                }

                RaisePropertyChanging(PatientNumberInitializedSequencePropertyName);
                _patientNumberInitializedSequence = value;
                RaisePropertyChanged(PatientNumberInitializedSequencePropertyName);
            }
        }

        /// <summary>
        /// The <see cref="PatientNumberInitializedSequenceList" /> property's name.
        /// </summary>
        public const string PatientNumberInitializedSequenceListPropertyName = "PatientNumberInitializedSequenceList";

        private ObservableCollection<string> _patientNumberInitializedSequenceList = new ObservableCollection<string>();

        /// <summary>
        /// Sets and gets the PatientNumberInitializedSequenceList property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public ObservableCollection<string> PatientNumberInitializedSequenceList
        {
            get
            {
                return _patientNumberInitializedSequenceList;
            }

            set
            {
                if (_patientNumberInitializedSequenceList == value)
                {
                    return;
                }

                RaisePropertyChanging(PatientNumberInitializedSequenceListPropertyName);
                _patientNumberInitializedSequenceList = value;
                RaisePropertyChanged(PatientNumberInitializedSequenceListPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="SerialPortNameList" /> property's name.
        /// </summary>
        public const string SerialPortNameListPropertyName = "SerialPortNameList";

        private ObservableCollection<string> _serialPortNameList = new ObservableCollection<string>();

        /// <summary>
        /// Sets and gets the SerialPortNameList property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public ObservableCollection<string> SerialPortNameList
        {
            get
            {
                return _serialPortNameList;
            }

            set
            {
                if (_serialPortNameList == value)
                {
                    return;
                }

                RaisePropertyChanging(SerialPortNameListPropertyName);
                _serialPortNameList = value;
                RaisePropertyChanged(SerialPortNameListPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="SerialPortName" /> property's name.
        /// </summary>
        public const string SerialPortNamePropertyName = "SerialPortName";

        private string _serialPortName = string.Empty;

        /// <summary>
        /// Sets and gets the SerialPortName property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string SerialPortName
        {
            get
            {
                return _serialPortName;
            }

            set
            {
                if (_serialPortName == value)
                {
                    return;
                }

                RaisePropertyChanging(SerialPortNamePropertyName);
                _serialPortName = value;
                RaisePropertyChanged(SerialPortNamePropertyName);
            }
        }

        /// <summary>
        /// The <see cref="CompanyName" /> property's name.
        /// </summary>
        public const string CompanyNamePropertyName = "CompanyName";

        private string _companyName = string.Empty;

        /// <summary>
        /// Sets and gets the CompanyName property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string CompanyName
        {
            get
            {
                return _companyName;
            }

            set
            {
                if (_companyName == value)
                {
                    return;
                }

                RaisePropertyChanging(CompanyNamePropertyName);
                _companyName = value;
                RaisePropertyChanged(CompanyNamePropertyName);
            }
        }

        /// <summary>
        /// The <see cref="CompanyLogoFileFullName" /> property's name.
        /// </summary>
        public const string CompanyLogoFileFullNamePropertyName = "CompanyLogoFileFullName";

        private string _companyLogoFileFullName = string.Empty;

        /// <summary>
        /// Sets and gets the CompanyLogoFileFullName property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string CompanyLogoFileFullName
        {
            get
            {
                return _companyLogoFileFullName;
            }

            set
            {
                if (_companyLogoFileFullName == value)
                {
                    return;
                }

                RaisePropertyChanging(CompanyLogoFileFullNamePropertyName);
                _companyLogoFileFullName = value;
                RaisePropertyChanged(CompanyLogoFileFullNamePropertyName);
            }
        }

        /// <summary>
        /// The <see cref="CompanyAddress" /> property's name.
        /// </summary>
        public const string CompanyAddressPropertyName = "CompanyAddress";

        private string _companyAddress = string.Empty;

        /// <summary>
        /// Sets and gets the CompanyAddress property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string CompanyAddress
        {
            get
            {
                return _companyAddress;
            }

            set
            {
                if (_companyAddress == value)
                {
                    return;
                }

                RaisePropertyChanging(CompanyAddressPropertyName);
                _companyAddress = value;
                RaisePropertyChanged(CompanyAddressPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="CompanyPhoneNumber" /> property's name.
        /// </summary>
        public const string CompanyPhoneNumberPropertyName = "CompanyPhoneNumber";

        private string _companyPhoneNumber = string.Empty;

        /// <summary>
        /// Sets and gets the CompanyPhoneNumber property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string CompanyPhoneNumber
        {
            get
            {
                return _companyPhoneNumber;
            }

            set
            {
                if (_companyPhoneNumber == value)
                {
                    return;
                }

                RaisePropertyChanging(CompanyPhoneNumberPropertyName);
                _companyPhoneNumber = value;
                RaisePropertyChanged(CompanyPhoneNumberPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="TestReportTitle" /> property's name.
        /// </summary>
        public const string TestReportTitlePropertyName = "TestReportTitle";

        private string _testReportTitle = string.Empty;

        /// <summary>
        /// Sets and gets the TestReportTitle property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string TestReportTitle
        {
            get
            {
                return _testReportTitle;
            }

            set
            {
                if (_testReportTitle == value)
                {
                    return;
                }

                RaisePropertyChanging(TestReportTitlePropertyName);
                _testReportTitle = value;
                RaisePropertyChanged(TestReportTitlePropertyName);
            }
        }

        /// <summary>
        /// The <see cref="DepartmentName" /> property's name.
        /// </summary>
        public const string DepartmentNamePropertyName = "DepartmentName";

        private string _departmentName = string.Empty;

        /// <summary>
        /// Sets and gets the DepartmentName property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string DepartmentName
        {
            get
            {
                return _departmentName;
            }

            set
            {
                if (_departmentName == value)
                {
                    return;
                }

                RaisePropertyChanging(DepartmentNamePropertyName);
                _departmentName = value;
                RaisePropertyChanged(DepartmentNamePropertyName);
            }
        }

        private RelayCommand _saveCommand;

        /// <summary>
        /// Gets the SaveCommand.
        /// </summary>
        public RelayCommand SaveCommand
        {
            get
            {
                return _saveCommand
                    ?? (_saveCommand = new RelayCommand(
                                          () =>
                                          {
                                              try
                                              {
                                                  _basicConfigurationService.Save(GetProperties());

                                                  // Send ReturnHomeMessage to PageBase.
                                                  Messenger.Default.Send<int>(0, MainViewModel.ReturnHomeMessageToken);
                                              }
                                              catch (Exception ex)
                                              {
                                                  RequestDisplayErrorMessage(ex.Message);
                                              }
                                          }));
            }
        }

        /// <summary>
        /// Generate the PatientNumberInitializedSequenceList list.
        /// </summary>
        private void GeneratePatientNumberInitializedSequenceList()
        {
            PatientNumberInitializedSequenceList.Clear();

            PatientNumberInitializedSequenceList.Add("01");
            PatientNumberInitializedSequenceList.Add("001");
            PatientNumberInitializedSequenceList.Add("0001");
            PatientNumberInitializedSequenceList.Add("00001");
            PatientNumberInitializedSequenceList.Add("000001");
        }

        /// <summary>
        /// Generate the Serial port name list from COM1 to COM9.
        /// </summary>
        private void GenerateSerialPortNameList()
        {
            SerialPortNameList.Clear();

            for (int i = 1; i <= 9; i++)
            {
                SerialPortNameList.Add("COM" + i.ToString());
            }
        }

        /// <summary>
        /// Set current all properties based on provided instance of BasicConfiguration.
        /// </summary>
        /// <param name="entity">The instance of BasicConfiguration that contains all data.</param>
        private void SetProperties(BasicConfiguration entity)
        {
            PatientNumberPrefix = entity.PatientNumberPrefix;
            PatientNumberContainsYear = entity.PatientNumberContainsYear;
            PatientNumberContainsMonth = entity.PatientNumberContainsMonth;
            PatientNumberContainsDay = entity.PatientNumberContainsDay;
            PatientNumberInitializedSequence = entity.PatientNumberInitializedSequence;

            CompanyName = entity.CompanyName;
            CompanyAddress = entity.CompanyAddress;
            CompanyLogoFileFullName = entity.CompanyLogoFileFullName;
            CompanyPhoneNumber = entity.CompanyPhoneNumber;
            TestReportTitle = entity.TestReportTitle;
            DepartmentName = entity.DepartmentName;
        }

        /// <summary>
        /// Get current all properties' values and return the instance of BasicConfiguration.
        /// </summary>
        /// <returns>The instance of BasicConfiguration contains all data.</returns>
        private BasicConfiguration GetProperties()
        {
            return new BasicConfiguration
            {
                PatientNumberPrefix = PatientNumberPrefix,
                PatientNumberContainsYear = PatientNumberContainsYear,
                PatientNumberContainsMonth = PatientNumberContainsMonth,
                PatientNumberContainsDay = PatientNumberContainsDay,
                PatientNumberInitializedSequence = PatientNumberInitializedSequence,
                CompanyName = CompanyName,
                CompanyAddress = CompanyAddress,
                CompanyLogoFileName = (new FileInfo(CompanyLogoFileFullName)).Name,
                CompanyLogoFileFullName = CompanyLogoFileFullName,
                CompanyPhoneNumber = CompanyPhoneNumber,
                TestReportTitle = TestReportTitle,
                DepartmentName = DepartmentName
            };
        }
    }
}